/*
 * Quantity.h
 *
 *  Created on: Mar 9, 2011
 *      Author: topcoder
 */

#ifndef QUANTITY_H_
#define QUANTITY_H_

#include "math.h"
#include "float.h"
#include "iostream"
using namespace std;

template <class Unit>
class Quantity;

template <class Unit>
ostream& operator << (ostream& out, const Quantity <Unit>& quantity);

template<class Unit> 
class Quantity {
public:
    Quantity(const unsigned int amount,const Unit unit);
    bool operator == (const Quantity& quantity) const;
    Quantity operator + (const Quantity& quantity) const;
    Quantity operator % (const Quantity& quantity) const;
    unsigned int operator / (const Quantity& quantity) const;
    ostream& outputQuantityInXUnit(ostream& os,const Unit& unit) const;

    friend ostream& operator << <>(ostream& os, const Quantity<Unit>& quantity);

private:
    unsigned int amount_m;
    Unit unit_m;
};

template<class Unit> 
Quantity<Unit>::Quantity(const unsigned int amount, const Unit unit):\
     unit_m(unit)
{
    amount_m = unit.toAmountInBaseUnit(amount);
}

template<class Unit> 
bool Quantity<Unit>::operator == (const Quantity& quantity) const
{
    return amount_m == quantity.amount_m;
}

template<class Unit> 
Quantity<Unit> Quantity<Unit>::operator + (const Quantity& quantity) const
{
    unsigned int amount = unit_m.toAmountInThisUnit(amount_m + quantity.amount_m);
    return Quantity(amount, this->unit_m);
}

template<class Unit> 
Quantity<Unit> Quantity<Unit>::operator % (const Quantity& quantity) const
{
    unsigned int amount = unit_m.toAmountInThisUnit(amount_m%quantity.amount_m);
    return Quantity(amount, this->unit_m);
}

template<class Unit> 
unsigned int Quantity<Unit>::operator / (const Quantity& quantity) const
{
     return (amount_m/quantity.amount_m);
}

template<class Unit> 
ostream& operator << (ostream& os, const Quantity<Unit>& quantity)
{
    if(quantity.amount_m)
    {
        os << quantity.unit_m.toAmountInThisUnit(quantity.amount_m) << " " << quantity.unit_m << " ";
    }
    
    return os;
}

template<class Unit> 
ostream& Quantity<Unit>::outputQuantityInXUnit(ostream& os,const Unit& unit) const
{
    os << Quantity((*this)/Quantity(1,unit),unit);
    return os;
}

#endif /* QUANTITY_H_ */



